<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8">
<title>Minimize sidelobe level of a uniform linear array via spectral factorization</title>
<link rel="canonical" href="http://cvxr.com/cvx/examples/antenna_array_design/html/line_array_spec_fact.html">
<link rel="stylesheet" href="../../examples.css" type="text/css">
</head>
<body>
<div id="header">
<h1>Minimize sidelobe level of a uniform linear array via spectral factorization</h1>
Jump to:&nbsp;&nbsp;&nbsp;&nbsp;
<a href="#source">Source code</a>&nbsp;&nbsp;&nbsp;&nbsp;
<a href="#output">Text output</a>
&nbsp;&nbsp;&nbsp;&nbsp;
<a href="#plots">Plots</a>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="../../index.html">Library index</a>
</div>
<div id="content">
<a id="source"></a>
<pre class="codeinput">
<span class="comment">% "FIR Filter Design via Spectral Factorization and Convex Optimization" example</span>
<span class="comment">% by S.-P. Wu, S. Boyd, and L. Vandenberghe</span>
<span class="comment">% (figures are generated)</span>
<span class="comment">%</span>
<span class="comment">% Designs a uniform linear antenna array using spectral factorization method where:</span>
<span class="comment">% - it minimizes sidelobe level outside the beamwidth of the pattern</span>
<span class="comment">% - it has a constraint on the maximum ripple around unit gain in the beamwidth</span>
<span class="comment">%</span>
<span class="comment">%   minimize   max |y(theta)|                   for theta in the stop-beamwidth</span>
<span class="comment">%       s.t.   1/delta &lt;= |y(theta)| &lt;= delta   for theta in the pass-beamwidth</span>
<span class="comment">%</span>
<span class="comment">% We first replace the look-angle variable theta with the "frequency"</span>
<span class="comment">% variable omega, defined by omega = -2*pi*d/lambda*cos(theta).</span>
<span class="comment">% This transforms the antenna pattern y(theta) into a standard discrete</span>
<span class="comment">% Fourier transform of array weights w. Then we apply another change of</span>
<span class="comment">% variables: we replace w with its auto-correlation coefficients r.</span>
<span class="comment">%</span>
<span class="comment">% Now the problem can be solved via spectral factorization approach:</span>
<span class="comment">%</span>
<span class="comment">%   minimize   max R(omega)                        for omega in the stopband</span>
<span class="comment">%       s.t.   (1/delta)^2 &lt;= R(omega) &lt;= delta^2  for omega in the passband</span>
<span class="comment">%              R(omega) &gt;= 0                       for all omega</span>
<span class="comment">%</span>
<span class="comment">% where R(omega) is the squared magnitude of the y(theta) array response</span>
<span class="comment">% (and the Fourier transform of the autocorrelation coefficients r).</span>
<span class="comment">% Variables are coefficients r. delta is the allowed passband ripple.</span>
<span class="comment">% This is a convex problem (can be formulated as an LP after sampling).</span>
<span class="comment">%</span>
<span class="comment">% Written for CVX by Almir Mutapcic 02/02/06</span>

<span class="comment">%********************************************************************</span>
<span class="comment">% problem specs: a uniform line array with inter-element spacing d</span>
<span class="comment">%                antenna element locations are at d*[0:n-1]</span>
<span class="comment">%                (the array pattern will be symmetric around origin)</span>
<span class="comment">%********************************************************************</span>
n = 20;               <span class="comment">% number of antenna elements</span>
lambda = 1;           <span class="comment">% wavelength</span>
d = 0.45*lambda;      <span class="comment">% inter-element spacing</span>

<span class="comment">% passband direction from 30 to 60 degrees (30 degrees bandwidth)</span>
<span class="comment">% transition band is 15 degrees on both sides of the passband</span>
theta_pass = 40;
theta_stop = 50;

<span class="comment">% passband max allowed ripple</span>
ripple = 0.1; <span class="comment">% in dB (+/- around the unit gain)</span>

<span class="comment">%********************************************************************</span>
<span class="comment">% construct optimization data</span>
<span class="comment">%********************************************************************</span>
<span class="comment">% number of frequency samples</span>
m = 30*n;

<span class="comment">% convert passband and stopband angles into omega frequencies</span>
omega_zero = -2*pi*d/lambda;
omega_pass = -2*pi*d/lambda*cos(theta_pass*pi/180);
omega_stop = -2*pi*d/lambda*cos(theta_stop*pi/180);
omega_pi   = +2*pi*d/lambda;

<span class="comment">% build matrix A that relates R(omega) and r, ie, R = A*r</span>
omega = linspace(-pi,pi,m)';
A = exp( -j*omega(:)*[1-n:n-1] );

<span class="comment">% passband constraint matrix</span>
Ap = A(omega &gt;= omega_zero &amp; omega &lt;= omega_pass,:);

<span class="comment">% stopband constraint matrix</span>
As = A(omega &gt;= omega_stop &amp; omega &lt;= omega_pi,:);

<span class="comment">%********************************************************************</span>
<span class="comment">% formulate and solve the magnitude design problem</span>
<span class="comment">%********************************************************************</span>
cvx_begin
  variable <span class="string">r(2*n-1,1)</span> <span class="string">complex</span>
  <span class="comment">% minimize stopband attenuation</span>
  minimize( max( real( As*r ) ) )
  subject <span class="string">to</span>
    <span class="comment">% passband ripple constraints</span>
    (10^(-ripple/20))^2 &lt;= real( Ap*r ) &lt;= (10^(+ripple/20))^2;
    <span class="comment">% nonnegative-real constraint for all frequencies</span>
    <span class="comment">% a bit redundant: the passband frequencies are already constrained</span>
    real( A*r ) &gt;= 0;
    <span class="comment">% auto-correlation symmetry constraints</span>
    imag(r(n)) == 0;
    r(n-1:-1:1) == conj(r(n+1:end));
cvx_end

<span class="comment">% check if problem was successfully solved</span>
<span class="keyword">if</span> ~strfind(cvx_status,<span class="string">'Solved'</span>)
    <span class="keyword">return</span>
<span class="keyword">end</span>

<span class="comment">% find antenna weights by computing the spectral factorization</span>
w = spectral_fact(r);

<span class="comment">% divided by 2 since this is in PSD domain</span>
min_sidelobe_level = 10*log10( cvx_optval );
fprintf(1,<span class="string">'The minimum sidelobe level is %3.2f dB.\n\n'</span>,<span class="keyword">...</span>
          min_sidelobe_level);

<span class="comment">%********************************************************************</span>
<span class="comment">% plots</span>
<span class="comment">%********************************************************************</span>
<span class="comment">% build matrix G that relates y(theta) and w, ie, y = G*w</span>
theta = [-180:180]';
G = kron( cos(pi*theta/180), [0:n-1] );
G = exp(2*pi*i*d/lambda*G);
y = G*w;

<span class="comment">% plot array pattern</span>
figure(1), clf
ymin = -40; ymax = 5;
plot([-180:180], 20*log10(abs(y)), <span class="keyword">...</span>
     [theta_stop theta_stop],[ymin ymax],<span class="string">'r--'</span>,<span class="keyword">...</span>
     [-theta_pass -theta_pass],[ymin ymax],<span class="string">'r--'</span>,<span class="keyword">...</span>
     [-theta_stop -theta_stop],[ymin ymax],<span class="string">'r--'</span>,<span class="keyword">...</span>
     [theta_pass theta_pass],[ymin ymax],<span class="string">'r--'</span>);
xlabel(<span class="string">'look angle'</span>), ylabel(<span class="string">'mag y(theta) in dB'</span>);
axis([-180 180 ymin ymax]);

<span class="comment">% polar plot</span>
figure(2), clf
zerodB = 50;
dBY = 20*log10(abs(y)) + zerodB;
plot(dBY.*cos(pi*theta/180), dBY.*sin(pi*theta/180), <span class="string">'-'</span>);
axis([-zerodB zerodB -zerodB zerodB]), axis(<span class="string">'off'</span>), axis(<span class="string">'square'</span>)
hold <span class="string">on</span>
plot(zerodB*cos(pi*theta/180),zerodB*sin(pi*theta/180),<span class="string">'k:'</span>) <span class="comment">% 0 dB</span>
plot( (min_sidelobe_level + zerodB)*cos(pi*theta/180), <span class="keyword">...</span>
      (min_sidelobe_level + zerodB)*sin(pi*theta/180),<span class="string">'k:'</span>)  <span class="comment">% min level</span>
text(-zerodB,0,<span class="string">'0 dB'</span>)
text(-(min_sidelobe_level + zerodB),0,sprintf(<span class="string">'%0.1f dB'</span>,min_sidelobe_level));
plot([0 60*cos(theta_pass*pi/180)], [0 60*sin(theta_pass*pi/180)], <span class="string">'k:'</span>)
plot([0 60*cos(-theta_pass*pi/180)],[0 60*sin(-theta_pass*pi/180)],<span class="string">'k:'</span>)
plot([0 60*cos(theta_stop*pi/180)], [0 60*sin(theta_stop*pi/180)], <span class="string">'k:'</span>)
plot([0 60*cos(-theta_stop*pi/180)],[0 60*sin(-theta_stop*pi/180)],<span class="string">'k:'</span>)
hold <span class="string">off</span>
</pre>
<a id="output"></a>
<pre class="codeoutput">
 
Calling SDPT3: 1171 variables, 40 equality constraints
   For improved efficiency, SDPT3 is solving the dual problem.
------------------------------------------------------------

 num. of constraints = 40
 dim. of linear var  = 1171
*******************************************************************
   SDPT3: Infeasible path-following algorithms
*******************************************************************
 version  predcorr  gam  expon  scale_data
    NT      1      0.000   1        0    
it pstep dstep pinfeas dinfeas  gap      prim-obj      dual-obj    cputime
-------------------------------------------------------------------
 0|0.000|0.000|1.0e+04|1.4e+02|2.0e+06| 1.008655e+02  0.000000e+00| 0:0:00| chol  1  1 
 1|0.875|0.762|1.3e+03|3.4e+01|3.1e+05| 1.707706e+03 -8.318726e+01| 0:0:00| chol  1  1 
 2|0.763|0.812|3.0e+02|6.5e+00|8.5e+04| 2.032831e+03 -1.284834e+02| 0:0:00| chol  1  1 
 3|0.879|0.798|3.6e+01|1.3e+00|1.4e+04| 1.364175e+03 -1.494646e+02| 0:0:00| chol  1  1 
 4|0.662|0.834|1.2e+01|2.3e-01|5.5e+03| 8.085569e+02 -2.002852e+02| 0:0:00| chol  1  1 
 5|0.934|1.000|8.1e-01|2.4e-03|6.0e+02| 1.565080e+02 -1.927015e+02| 0:0:00| chol  1  2 
 6|0.903|0.981|7.9e-02|2.8e-04|1.1e+02| 2.233472e+01 -7.632889e+01| 0:0:00| chol  2  1 
 7|0.862|1.000|1.1e-02|1.6e-02|6.9e+01| 1.487218e+01 -5.065246e+01| 0:0:00| chol  1  1 
 8|0.930|0.941|7.7e-04|3.1e-03|4.5e+00| 1.679598e+00 -2.798362e+00| 0:0:00| chol  1  1 
 9|0.473|0.949|4.0e-04|3.1e-04|2.4e+00| 9.986218e-01 -1.431647e+00| 0:0:00| chol  1  1 
10|0.872|1.000|5.2e-05|8.1e-05|1.2e+00| 2.761667e-01 -8.786424e-01| 0:0:00| chol  1  1 
11|0.951|0.988|2.5e-06|1.1e-05|1.9e-01| 6.218113e-02 -1.316350e-01| 0:0:00| chol  1  1 
12|0.662|1.000|8.5e-07|5.0e-07|8.7e-02| 2.910117e-02 -5.759656e-02| 0:0:00| chol  1  1 
13|0.847|0.705|1.3e-07|3.2e-07|4.4e-02| 8.825548e-03 -3.492830e-02| 0:0:00| chol  1  1 
14|1.000|0.570|6.6e-14|1.6e-07|2.9e-02| 4.098110e-03 -2.443245e-02| 0:0:00| chol  1  1 
15|1.000|1.000|4.9e-14|1.2e-12|1.4e-02| 2.591040e-03 -1.164488e-02| 0:0:00| chol  1  1 
16|1.000|0.990|3.2e-14|1.0e-12|6.3e-03| 3.772455e-04 -5.904202e-03| 0:0:00| chol  1  1 
17|0.404|1.000|8.2e-14|1.0e-12|4.7e-03|-4.331405e-04 -5.174142e-03| 0:0:00| chol  1  1 
18|0.807|1.000|9.7e-14|1.0e-12|2.4e-03|-1.819613e-03 -4.250844e-03| 0:0:00| chol  1  1 
19|0.980|0.981|4.6e-13|1.0e-12|7.3e-04|-2.854651e-03 -3.581003e-03| 0:0:00| chol  1  1 
20|0.572|0.971|1.8e-12|1.0e-12|3.6e-04|-3.103962e-03 -3.459133e-03| 0:0:00| chol  1  1 
21|0.827|0.950|4.8e-13|1.1e-12|9.7e-05|-3.339091e-03 -3.436323e-03| 0:0:00| chol  1  1 
22|0.970|0.894|5.1e-12|1.1e-12|9.6e-06|-3.419536e-03 -3.429101e-03| 0:0:00| chol  1  1 
23|0.866|0.886|2.3e-12|1.1e-12|1.8e-06|-3.426509e-03 -3.428273e-03| 0:0:00| chol  1  1 
24|0.979|0.983|1.5e-12|1.0e-12|8.9e-08|-3.428062e-03 -3.428151e-03| 0:0:00| chol  1  1 
25|0.992|0.993|1.3e-12|1.0e-12|1.8e-09|-3.428145e-03 -3.428147e-03| 0:0:00|
  stop: max(relative gap, infeasibilities) &lt; 1.49e-08
-------------------------------------------------------------------
 number of iterations   = 25
 primal objective value = -3.42814510e-03
 dual   objective value = -3.42814686e-03
 gap := trace(XZ)       = 1.76e-09
 relative gap           = 1.74e-09
 actual relative gap    = 1.74e-09
 rel. primal infeas     = 1.31e-12
 rel. dual   infeas     = 1.01e-12
 norm(X), norm(y), norm(Z) = 7.2e-01, 2.9e-01, 9.2e+00
 norm(A), norm(b), norm(C) = 3.0e+02, 2.0e+00, 1.2e+01
 Total CPU time (secs)  = 0.33  
 CPU time per iteration = 0.01  
 termination code       =  0
 DIMACS: 1.3e-12  0.0e+00  6.1e-12  0.0e+00  1.7e-09  1.7e-09
-------------------------------------------------------------------
------------------------------------------------------------
Status: Solved
Optimal value (cvx_optval): +0.00342815
 
The minimum sidelobe level is -24.65 dB.

</pre>
<a id="plots"></a>
<div id="plotoutput">
<img src="line_array_spec_fact__01.png" alt=""> <img src="line_array_spec_fact__02.png" alt=""> 
</div>
</div>
</body>
</html>